package com.sql;

import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.ForeignKey;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
import java.io.File;
import java.io.FileWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: sxlju_000
 * Date: 13-11-1
 * Time: 下午9:54
 * To change this template use File | Settings | File Templates.
 */
public class GernateDataBase {
    private ClassMeta classMetaList;

    public ClassMeta getClassMetaList() {
        return classMetaList;
    }


    public void generate() throws Exception {
        Map root = new HashMap();
        List<ClassMeta> classMetas = new ArrayList<ClassMeta>();
        Map<String, ClassMeta> persistenceMap = this.createPersistenceMap();
        for (ClassMeta classMeta : persistenceMap.values()) {
            classMetas.add(classMeta);
        }
        root.put("classMetas", classMetas);
        File templateDir = new File(System.getProperty("user.dir") + "/easyui_server/src/main/resources");
        //定义输出
        freemarker.template.Configuration cfg = FreeMarkerHelp.getCfg();
        //从什么地方加载模板文件
        cfg.setDirectoryForTemplateLoading(templateDir);
        //加载模板
        Template template = cfg.getTemplate("database_sql.ftl");
        //定义数据
        File sqlFileDir = new File("sqlFile");
        if (!sqlFileDir.exists()) {
            sqlFileDir.mkdir();
        }
        Writer out = new FileWriter(sqlFileDir + "/" + this.getSplitLast(System.getProperty("user.dir"), "\\") + ".generator.sql");
        template.process(root, out);
        out.flush();
        out.close();
    }

    private File[] getToDealFiles() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        URL url = loader.getResource("");
        assert url != null;
        File urlFile = null;
        try {
            urlFile = new File(url.toURI());
        } catch (URISyntaxException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        File[] files = urlFile.listFiles();
        return files;
    }

    public Map<String, ClassMeta> createPersistenceMap() {
        Map<String, ClassMeta> map = new HashMap<String, ClassMeta>();
        File[] files = getToDealFiles();
        for (File file : files)
            try {
                map = this.createPersistenceMap("", file, map);
            } catch (Exception e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        return map;
    }

    private Map<String, ClassMeta> createPersistenceMap(String packageName, File file, Map<String, ClassMeta> map) throws Exception {
        if (file.isFile()) {
            String fileName = file.getName();
            //判断类型<目前只遍历类>
            if (fileName.substring(fileName.lastIndexOf("."), fileName.length()).equals(".class")) {
                if (packageName != "") {
                    packageName += ".";
                }
                String className = packageName + fileName.replace(".class", "");
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Table.class)) {
                    //deal persistence bean
                    ClassMeta classMeta = new ClassMeta();
                    String tableName = clazz.getAnnotation(Table.class).name();
                    if (StringUtils.isBlank(tableName)) {
                        tableName = clazz.getSimpleName();
                    }
                    classMeta.setTableName(tableName);
                    List<FieldMeta> fieldMetas = new ArrayList<FieldMeta>();
                    fieldMetas = this.createFieldMetas(clazz, fieldMetas);
                    classMeta.setFieldMetas(fieldMetas);
                    map.put(clazz.getSimpleName(), classMeta);
                }
            }
        } else {
            File[] files = file.listFiles();
            if (packageName != "") {
                packageName += ".";
            }
            packageName += file.getName();
            for (File f : files) {
                createPersistenceMap(packageName, f, map);
            }
        }
        return map;
        //To change body of created methods use File | Settings | File Templates..
    }

    private List<FieldMeta> createFieldMetas(Class<?> clazz, List<FieldMeta> fieldMetas) throws ClassNotFoundException, NoSuchMethodException {
        if (!clazz.equals(Object.class)) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                FieldMeta fieldMeta = new FieldMeta();
                field.setAccessible(true);
                Method method = clazz.getDeclaredMethod("get" + this.transformerStringToUpper(field.getName()));
                if (method.isAnnotationPresent(Column.class)) {
                    if (method.isAnnotationPresent(Id.class)) {
                        fieldMeta.setPrimaryKey(true);
                    }
                          /* String columnName = field.getAnnotation(Column.class).name();
                    if (StringUtils.isBlank(columnName)) {
                        columnName = field.getName();
                    }*/
                    String columnName = field.getName();
                    fieldMeta.setColumnName(columnName);
                } else {
                    if (method.isAnnotationPresent(ForeignKey.class)) {
                        ForeignKeyMeta foreignKeyMeta = new ForeignKeyMeta();
                        String foreignKeyName = method.getAnnotation(ForeignKey.class).name();
                        String tableName = clazz.getAnnotation(Table.class).name();
                        if (StringUtils.isBlank(tableName)) {
                            tableName = clazz.getSimpleName();
                        }
                       /* foreignKeyName = "FK_" + tableName + "_" + field.getName() + "_id"; //
                        String foreignKeyId = field.getAnnotation(ForeignKey.class).foreignKeyId();
                        if (StringUtils.isBlank(foreignKeyId)) {
                            foreignKeyId = field.getName() + "_id";
                        }*/
                        String foreignKeyId = field.getName() + "_id";
                      /*  String refrencesId = field.getAnnotation(ForeignKey.class).refrencesId();
                        if (StringUtils.isBlank(refrencesId)) {
                            refrencesId = "id";
                        }*/
                        String refrencesId = "id";
                        String referencesTableName = Class.forName(field.getType().getName()).getAnnotation(Table.class).name();
                        foreignKeyMeta.setReferencesTableName(referencesTableName);
                        foreignKeyMeta.setForeignKeyId(foreignKeyId);
                        foreignKeyMeta.setReferencesId(refrencesId);
                        foreignKeyMeta.setForeignKeyName(foreignKeyName);
                        fieldMeta.setForeignKeyMeta(foreignKeyMeta);
                        fieldMeta.setColumnName(method.getAnnotation(JoinColumn.class).name());
                    }
                }



                 /*   String type = field.getAnnotation(Column.class).type();
                    if (StringUtils.isBlank(type)) {
                        type = MySqlTypeHelper.getMySqlType(field.getType().getName());
                    }*/
                String type = MySqlTypeHelper.getMySqlType(field.getType().getName());
                  /*  String lengthStr = field.getAnnotation(Column.class).length();
                    Long length = 0L;
                    if (StringUtils.isBlank(lengthStr)) {
                        length = MySqlTypeHelper.getMySqlLength(field.getType().getName());
                    }*/
                Long length = MySqlTypeHelper.getMySqlLength(field.getType().getName());
                  /*  String defaultValue = field.getAnnotation(Column.class).defaultValue();
                    if (StringUtils.isBlank(defaultValue)) {
                        defaultValue = MySqlTypeHelper.getMySqlDefaultValue(field);
                    }*/
                String defaultValue = MySqlTypeHelper.getMySqlDefaultValue(field);

                if (!StringUtils.isBlank(defaultValue)) {
                    fieldMeta.setDefaultValue(defaultValue);
                }
//                    boolean isNull = field.getAnnotation(Column.class).isNull();
                boolean isNull = true;

                fieldMeta.setFieldName(field.getName());
                fieldMeta.setType(type);
                fieldMeta.setLength(length);
                fieldMeta.setNull(Boolean.valueOf(isNull));
                fieldMetas.add(fieldMeta);
            }

            this.createFieldMetas(clazz.getSuperclass(), fieldMetas);
        }
        return fieldMetas;
    }


    public String transformerStringToUpper(String string) {
        return string.substring(0, 1).toUpperCase() + string.substring(1);
    }

    public String getSplitLast(String str, String o) {
        int i = str.lastIndexOf(o);
        String substring = str.substring(i + 1);
        return substring;
    }

    public static void main(String[] args) throws Exception {
        GernateDataBase gernateDataBase = new GernateDataBase();
//        gernateDataBase.gernateTable();
        gernateDataBase.generate();
    }


}
